package com.doeis.minaserver.packet;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.Timestamp;

import com.alibaba.fastjson.JSON;
import com.doeis.common.utils.StringUtils;
import com.doeis.minaserver.bean.BasicBean;

/**
 * 基本数据包，指定数据类型，版本号，数据从哪里来，到哪里去,数据是什么。
 * 
 * @author nortan
 *
 */
public abstract class Packet implements Cloneable {
	
	
	// 服务器的id号
	public static final String SERVER_ID = "0000";
	public static final String WEB_SERVER_ID = "0001";
	
	 // 数据包默认编码
	public static final String DEFAULT_CHARSET = "UTF-8";
	
	//报文头数据长度，以byte为单位，修改数据包头时，需要修改他的长度
	public static final int packetHeaderLength = 24;
	
	// 数据包类型,这里为枚举类型，枚举类型在发送时，占用一个byte的大小
	private PacketType packetType;   
	
	// 协议版本,占用一个字节
	private ProtocolVersion version;
	
	// 数据包发送方向，占用一个字节
	private Direction direction;
	
	private long time;
    /**
     * 执行的指令
     */
    private byte cmd;
    
    /**
     * 指令执行情况，0为未知，不知的情况一般是出服务器发出cmd请求，
     * 如果服务器处理的回复，必须已知了。
     */
    private int notifyType = 0;
    private TransType transType = TransType.p2p;
    
    private String from;
    private String to;
    private String pwd="";
    
	// 数据包体,数据包体是一个json数据包，发送过来的数据需要解析成json
	private String body = "{}";
	
	
	private Timestamp firstTime;	
	
	public Timestamp getFirstTime() {
		return firstTime;
	}

	public void setFirstTime(Timestamp firstTime) {
		this.firstTime = firstTime;
	}

	public PacketType getPacketType() {
		return packetType;
	}

	public void setPacketType(PacketType packetType) {
		this.packetType = packetType;
	}
	
	public Direction getDirection() {
		return direction;
	}

	public void setDirection(Direction direction) {
		this.direction = direction;
	}
	
	public byte getFromLen() {
		return (byte) from.getBytes().length;
	}

	public byte getToLen() {
		return (byte) to.getBytes().length;
	}
	
	public byte getPwdLen(){
		byte len = 0;
		try {
			if(!StringUtils.isBlank(pwd))
				len =(byte) pwd.getBytes(DEFAULT_CHARSET).length;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return len;
	}

	public String getFrom() {
		return from;
	}

	public void setFrom(String from) {
		this.from = from;
	}

	public String getTo() {
		return to;
	}

	public void setTo(String to) {
		this.to = to;
	}
	
	public String getPwd() {
		return pwd==null?"":pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	
	public int getLength() {
		int bodylen = 0;
		if( !StringUtils.isBlank(body) ){
			try {
				bodylen = getBody().getBytes(DEFAULT_CHARSET).length;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		return bodylen+getFromLen()+getToLen()+packetHeaderLength+getPwdLen();
	}
	
	public <T> T decoder(Class<T> beanClass) {
		return JSON.parseObject(getBody(), beanClass);
	}
	
	public void setBody(String body){
		this.body = body;
	}

	public void setBodyObj(BasicBean bodyBean) {		
		this.body = JSON.toJSONString(bodyBean);
	}
	
	public String getBody() {
//		try {
//			String msg = URLDecoder.decode(this.body,"utf-8");
//			return msg;
//		} catch (Exception e) {
//			return this.body;
//		}
		return this.body;
	}
	
	public byte getCmd() {
		return cmd;
	}

	public void setCmd(byte cmd) {
		this.cmd = cmd;
	}
	
	public int getNotifyType() {
		return notifyType;
	}

	public void setNotifyType(int notifyType) {
		this.notifyType = notifyType;
	}

	public ProtocolVersion getVersion() {
		return version;
	}

	public void setVersion(ProtocolVersion version) {
		this.version = version;
	}
	

	public TransType getTransType() {
		return transType;
	}

	public void setTransType(TransType transType) {
		this.transType = transType;
	}
	
	public long getTime() {
		return time;
	}

	public void setTime(long time) {
		this.time = time;
	}

	@Override
	public String toString(){
		StringBuffer sb = new StringBuffer();
		sb.append("[length:"+getLength());
		sb.append(", fromLen:"+getFromLen());
		sb.append(", toLen:"+getToLen());
		sb.append(", packetType:"+packetType);
		sb.append(", dire:"+getDirection());
		sb.append(", ver:"+getVersion());
		sb.append(", cmd:"+getCmd());
		sb.append(", notifyType:"+getNotifyType());
		sb.append(", transType:"+getTransType());
		sb.append(", time:"+getTime());
		sb.append(", from:"+getFrom());
		sb.append(", to:"+getTo());
		sb.append(", pwd:"+getPwd());
		sb.append(", body:"+body+"]");
		return sb.toString();
	}
	
	@Override
	public Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}

	/**
	 * 总包类型
	 * @author nortan
	 *
	 */
	public enum PacketType{
		//信息包
		info,
		//聊天信息包
		message,
		//组内聊天
		groupMsg,
		//组外聊天
		privateMsg,
		//系统的一些操作：清除缓存
		system
	}
	
	/**
	 * 发送方向，主要考虑以后有s->s的情况
	 * @author nortan
	 *
	 */
	public enum Direction{
		c2c,
		
		c2s,// 由客户端发向服务器的数据
		
		s2c,// 由服务器向客户端发送的数据包
		
		s2s;// 服务器到服务器的数据包
	}
	
	public enum ProtocolVersion{
		V1_0_0;
	}
	
	/**
	 * 数据包
	 * @author nortan
	 *
	 */
	public enum TransType{
		p2p,// 点对点
		p2g,// 点对组机
	}
}
